﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System.IO;
using System.Configuration;
namespace MigrateLinksofWIs
{
    class Program
    {
        static void Main(string[] args)
        {
            MigrateLinks();
            Console.WriteLine("Migration Completed.Press any key to exit...");
            Logging.Log("Migration Completed at "+DateTime.Now.ToString());
            Console.ReadLine();
        }

        private static void MigrateLinks()
        {
            List<SharedQueryInfo> lstqueryinfo = new List<SharedQueryInfo>();
            try
            {
                lstqueryinfo = getConfig();
                ProcessQueryFolder(lstqueryinfo);
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
                Logging.Log(ex.Message + "\n Stack Trace :" + ex.StackTrace);
            }
        }

        private static void ProcessQueryFolder(List<SharedQueryInfo> lstshareqryinfo)
        {
            WorkItemCollection SrcworkitemColl = null;
            WorkItem DestWI = null;
      
            try
            {


                Console.WriteLine("Preparing source TFS connection");
                QueryHierarchy sourceqryhirchy = getQueryHierarchy(getWorkItemStore(lstshareqryinfo[0].Serverurl), lstshareqryinfo[0].ProjectName);
                Console.WriteLine("Preparing target TFS connection");
                WorkItemStore destworkitemStore = getWorkItemStore(lstshareqryinfo[1].Serverurl);
                Console.WriteLine("Processing query folders and queries\n");
                QueryFolder sourcefolder = null;
             
                if (lstshareqryinfo[0].Subfolder == "")
                {
                    sourcefolder = getQueryFolder(sourceqryhirchy, lstshareqryinfo[0].Toplevelfolder);
                }
                else
                {
                    sourcefolder = initialFolder(getQueryFolder(sourceqryhirchy, lstshareqryinfo[0].Toplevelfolder), lstshareqryinfo[0].Subfolder);
                }

                WorkItemStore SrcworkitemStore = getWorkItemStore(lstshareqryinfo[0].Serverurl);

                foreach (QueryDefinition item in sourcefolder)
                {
                    Console.WriteLine("Executing query at " + sourcefolder.Path  + "::Query Name:" + item.Name);
                    Logging.Log ("Executing query at " + sourcefolder.Path  + "::Query Name:" + item.Name);
                    string qry = item.QueryText.Replace("@project", "'"+ConfigurationManager.AppSettings["SourceProject"].ToString()+"'");
                    SrcworkitemColl = SrcworkitemStore.Query(qry);
                    if (SrcworkitemColl.Count > 0)
                    {
                        foreach (WorkItem wi in SrcworkitemColl)
                        {
                            Console.WriteLine("Work Item :"+ wi.Id);
                            Logging.Log("Source Work Item :" + wi.Id);
                            //  Find related work item in destination TFS
                            DestWI = GetDestinationWorkItem(wi.Id, destworkitemStore);
                          
                            //Call Link migration method
                           
                                MigrateOtherLinks(wi, DestWI, destworkitemStore);
                                MigrateLinks (wi, DestWI,destworkitemStore );
                        
                           
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Logging.Log(ex.Message + "\n Stack Trace :" + ex.StackTrace);

            }
        }

        private static WorkItem GetDestinationWorkItem(int WiId,WorkItemStore  destworkitemStore)
        {
            WorkItem wi = null;
            WorkItemCollection dstworkitemcoll = null;
            try
            {
                
                string qrytext = ConfigurationManager.AppSettings["MigratedWIQry"].ToString();
                qrytext = qrytext.Replace("###WiID", WiId.ToString());
                dstworkitemcoll = destworkitemStore.Query(qrytext);
                if (dstworkitemcoll.Count==1)
                    {
                        wi = dstworkitemcoll[0];
                    }
                    
               
            }
            catch (Exception ex)
            {
               Console.WriteLine(ex.Message);
                Logging.Log(ex.Message + "\n Stack Trace :" + ex.StackTrace);
                
            }
            return wi;
        }

        private static QueryFolder initialFolder(QueryFolder parentFolder, string subFolder)
        {
            QueryFolder tmp = null;

            if (parentFolder.Contains(subFolder))
            {
                tmp = (QueryFolder)parentFolder[subFolder];
            }
            else
            {
                tmp = new QueryFolder(subFolder, parentFolder);
            }
            return tmp;
        }
        private static QueryFolder getQueryFolder(QueryHierarchy qryhirch, string toplevel)
        {
            QueryFolder objqryfolder = null;
            foreach (QueryFolder flder in qryhirch)
            {
                if (flder.Name == toplevel)
                {
                    objqryfolder = flder;
                }
            }
            return objqryfolder;

        }
        private static QueryHierarchy getQueryHierarchy(WorkItemStore objworkitemstore, string projectname)
        {
            ProjectCollection teamProjects = objworkitemstore.Projects;
            Project thisProject = teamProjects[projectname];
            return thisProject.QueryHierarchy;

        }
        private static WorkItemStore getWorkItemStore(string serverURI)
        {
            Console.WriteLine("Connecting to {0}...", serverURI);
            TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(serverURI));
            WorkItemStore SrcworkitemStore = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
            return SrcworkitemStore;
        }
      



        private static List<SharedQueryInfo> getConfig()
        {
            SharedQueryInfo SourceQueryInfo = new SharedQueryInfo();
            SharedQueryInfo DestinationQueryInfo = new SharedQueryInfo();
            List<SharedQueryInfo> lstsharedqryinfo = new List<SharedQueryInfo>();

            //Get Source Query Configurations
            SourceQueryInfo.Serverurl = ConfigurationManager.AppSettings["SourceTFSserverUrl"].ToString();
            SourceQueryInfo.ProjectName = ConfigurationManager.AppSettings["SourceProject"].ToString();
            SourceQueryInfo.Toplevelfolder = ConfigurationManager.AppSettings["SourceTopFolder"].ToString();
            SourceQueryInfo.Subfolder = ConfigurationManager.AppSettings["SourceSubFolder"].ToString();

            //Get Destination Query Configuration
            DestinationQueryInfo.Serverurl = ConfigurationManager.AppSettings["DestTFSserverUrl"].ToString();
            DestinationQueryInfo.ProjectName = ConfigurationManager.AppSettings["DestProject"].ToString();
            


            lstsharedqryinfo.Add(SourceQueryInfo);
            lstsharedqryinfo.Add(DestinationQueryInfo);
            return lstsharedqryinfo;
        }

        private static void MigrateNumInstance(WorkItem sourceWI, WorkItem destWI)
        {
            try
            {
                if(destWI !=null && destWI.Type.Name=="Bug")
                {
                    if (destWI.Fields["Num Instance"].Value==null)
                    { 
                       destWI.Open();
                       destWI.Fields["Num Instance"].Value   = sourceWI.Fields["Num Instance"].Value;
                       destWI.Save();
                       destWI.Close();
                       Console.WriteLine("Num Instance value saved from Source Work Item " + sourceWI.Id + " to Destination Work Item "+destWI.Id );
                       Logging.Log("Num Instance value saved from Source Work Item " + sourceWI.Id + " to Destination Work Item " + destWI.Id);
                    }
                }
                else
                {
                    Console.WriteLine("Work Item " + sourceWI.Id + " is not migrated in destination TFS.");
                    Logging.Log("Work Item " + sourceWI.Id + " is not migrated in destination TFS.");
                }
     
            }
            catch (Exception ex)
            {

                Logging.Log(ex.Message + " Stacktrace:" + ex.StackTrace);
            }
        }
        private static void MigrateReleaseTrain(WorkItem sourceWI, WorkItem destWI)
        {
            try
            {
                if (destWI != null )
                {
                    if (String.IsNullOrEmpty(Convert.ToString(destWI.Fields["Release Train"].Value) ))
                    {
                        destWI.Open();
                        destWI.Fields["Release Train"].Value = "Aluminum";//destWI.Fields["Milestone"].Value;
                        destWI.Save();
                        destWI.Close();
                        Console.WriteLine("Release Train value saved from Source Work Item " + sourceWI.Id + " to Destination Work Item " + destWI.Id);
                        Logging.Log("Release Train value saved from Source Work Item " + sourceWI.Id + " to Destination Work Item " + destWI.Id);
                    }
                }
                else
                {
                    Console.WriteLine("Work Item " + sourceWI.Id + " is not migrated in destination TFS.");
                    Logging.Log("Work Item " + sourceWI.Id + " is not migrated in destination TFS.");
                }

            }
            catch (Exception ex)
            {

                Logging.Log(ex.Message + " Stacktrace:" + ex.StackTrace);
            }
        }
        private static void MigrateLinks(WorkItem sourceWI, WorkItem destWI,WorkItemStore  destworkitemStore)
        {
            WorkItemLinkCollection sourcelinkcollec = null;
          
            WorkItem Linkworkitem = null;
            try
            {
                //  Get links of source work item
                sourcelinkcollec = sourceWI.WorkItemLinks;
                
                int linkcount = 0;
                if (destWI != null)
                {
                    foreach (WorkItemLink wilink in sourcelinkcollec)
                    {
                        linkcount++;
                        try
                        {
                            Console.WriteLine("Count:"+linkcount+"::: Linking  Work Item " + wilink.TargetId + " to destination work Item " + destWI.Id);
                            Logging.Log("Count:" + linkcount + "::: Linking  Work Item " + wilink.TargetId + " to destination work Item " + destWI.Id);
                            WorkItemLinkTypeEnd lnktypened = destworkitemStore.WorkItemLinkTypes.LinkTypeEnds[wilink.LinkTypeEnd.Name];
                            
                            Linkworkitem = GetDestinationWorkItem(wilink.TargetId, destworkitemStore);
                            if (Linkworkitem != null)
                            {
                                Console.WriteLine("Found migrated work item " + Linkworkitem.Id + " for source link work item " + wilink.TargetId);
                                Logging.Log("Found migrated work item " + Linkworkitem.Id + " for source link work item " + wilink.TargetId);
                                if (Islinkexists(Linkworkitem.Id,destWI )==false )
                                {
                                   
                                    destWI.Links.Add(new WorkItemLink(lnktypened, Linkworkitem.Id));
                                    destWI.Save();
                                    Console.WriteLine("Work Items Linked Successfully.Source Work Item:" + sourceWI.Id + "||Dest Work Item:" + destWI.Id + "||Linked Work Item:" + Linkworkitem.Id);
                                    Logging.Log("Work Items Linked Successfully.Source Work Item:" + sourceWI.Id + "||Dest Work Item:" + destWI.Id + "||Linked Work Item:" + Linkworkitem.Id);
                                }
                                else
                                {
                                    Console.WriteLine("Link already exists for work item. Source Work Item:" + sourceWI.Id + "||Dest Work Item:" + destWI.Id + "||Existing Linked Work Item:" + Linkworkitem.Id);
                                    Logging.Log("Link already exists for work item.Source Work Item:" + sourceWI.Id + "||Dest Work Item:" + destWI.Id + "||Existing Linked Work Item:" + Linkworkitem.Id);
                                }
                            }
                            else
                            {
                                Console.WriteLine("Linked Source Work Item " + wilink.TargetId + " is not migrated in destination TFS.");
                                Logging.Log("Linked Source Work Item " + wilink.TargetId + " is not migrated in destination TFS.");
                            }

                        }
                        catch (Exception ex)
                        {
                            destWI.Reset();
                            Console.WriteLine(ex.Message);
                            Logging.Log(ex.Message + "\n Stack Trace :" + ex.StackTrace);
                        }

                    }
                }
                else
                {
                    Console.WriteLine("Work Item "+sourceWI.Id+" is not migrated in destination TFS." );
                    Logging.Log("Work Item " + sourceWI.Id + " is not migrated in destination TFS.");
                }
                           
            }
            catch (Exception ex)
            {
                
                Logging.Log(ex.Message + " Stacktrace:" + ex.StackTrace);
            }
        }

        private static bool Islinkexists(int WIid,WorkItem destWI)
        { 
            bool isexists=false;
            WorkItemLinkCollection dstlinkcollec = null;
            dstlinkcollec = destWI.WorkItemLinks;
            foreach (WorkItemLink wilink in dstlinkcollec)
            {
                if (wilink.TargetId == WIid)
                {
                    isexists = true;
                    break;
                }
                else 
                {
                    isexists = false;
                }
            }
            return isexists;
        }
        private static void MigrateOtherLinks(WorkItem sourceWI, WorkItem destWI, WorkItemStore destworkitemStore)
        {
            try
            {
                
                LinkCollection lnkcoll = sourceWI.Links;
                foreach (Link item in lnkcoll )
                {

                    switch (item.BaseType)
                    {
                        case BaseLinkType.ExternalLink:
                             break;
                        case BaseLinkType.Hyperlink:
                             Hyperlink  hplnk =(Hyperlink )item;
                             Hyperlink hyplink = new Hyperlink(hplnk.Location);
                             destWI.Links.Add(hyplink);
                            destWI.Save();
                            break;
                        case BaseLinkType.RelatedLink:
                            break;
                        case BaseLinkType.WorkItemLink:
                            break;
                        default:
                            break;
                    }
                }

            }
            catch (Exception ex)
            {

                Logging.Log(ex.Message);
            }
        }

    }
    class SharedQueryInfo
    {
        public string Serverurl { get; set; }
        public string ProjectName { get; set; }
        public string Toplevelfolder { get; set; }
        public string Subfolder { get; set; }
    }
  
}
